/*
    This file is part of QTau
    Copyright (C) 2013-2018  Tobias "Tomoko" Platen <tplaten@posteo.de>
    Copyright (C) 2013       digited       <https://github.com/digited>
    Copyright (C) 2010-2013  HAL@ShurabaP  <https://github.com/haruneko>

    QTau is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    SPDX-License-Identifier: GPL-3.0+
*/

#include "maddewindow.h"
#include "ui_maddewindow.h"
#include <QCheckBox>
#include <QLabel>
#include <QKeyEvent>
#include <QFileDialog>
#include <QSettings>
#include <QMessageBox>

#include <formantmapwindow.h>

#define __devloglevel__ 6

MaddeWindow::MaddeWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MaddeWindow)
{
    ui->setupUi(this);
    this->setFixedHeight(this->height());
    this->setFixedWidth(this->width());

    _formantWindow = 0;

    for (int i = 0; i < MAXRECENTFILES; ++i) {
            _recentFileActs[i] = new QAction(this);
            _recentFileActs[i]->setVisible(false);
            this->ui->menuRecent_files->addAction(_recentFileActs[i]);
            connect(_recentFileActs[i], SIGNAL(triggered()),
                    this, SLOT(openRecentFile()));
   }

    updateRecentFileActions();
    setWindowTitle("MaddeLOID");

    this->ui->gridLayout->addWidget(new QLabel("Enable"),0,0);
    this->ui->gridLayout->addWidget(new QLabel("FRQ(Hz)"),1,0);
    this->ui->gridLayout->addWidget(new QLabel("VOL(dB)"),2,0);
    this->ui->gridLayout->addWidget(new QLabel("Q"),3,0);
    this->ui->gridLayout->addWidget(new QLabel("BW"),4,0);

    this->ui->gridLayout->addWidget(bindValue(new QCheckBox("F1"),"UseF1"),0,1,1,1);
    this->ui->gridLayout->addWidget(bindValue(new QCheckBox("F2"),"UseF2"),0,2,1,1);
    this->ui->gridLayout->addWidget(bindValue(new QCheckBox("F3"),"UseF3"),0,3,1,1);
    this->ui->gridLayout->addWidget(bindValue(new QCheckBox("F4"),"UseF4"),0,4,1,1);
    this->ui->gridLayout->addWidget(bindValue(new QCheckBox("F5"),"UseF5"),0,5,1,1);
    this->ui->gridLayout->addWidget(bindValue(new QCheckBox("F6"),"UseF6"),0,6,1,1);

    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"F1"),1,1,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"F2"),1,2,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"F3"),1,3,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"F4"),1,4,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"F5"),1,5,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"F6"),1,6,1,1);

    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"A1"),2,1,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"A2"),2,2,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"A3"),2,3,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"A4"),2,4,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"A5"),2,5,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"A6"),2,6,1,1);

    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"Q1"),3,1,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"Q2"),3,2,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"Q3"),3,3,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"Q4"),3,4,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"Q5"),3,5,1,1);
    this->ui->gridLayout->addWidget(bindValue(new KawaiiLineEdit(),"Q6"),3,6,1,1);

    this->ui->gridLayout->addWidget(bindValue(new QLabel("1"),"BW1"),4,1,1,1);
    this->ui->gridLayout->addWidget(bindValue(new QLabel("2"),"BW2"),4,2,1,1);
    this->ui->gridLayout->addWidget(bindValue(new QLabel("3"),"BW3"),4,3,1,1);
    this->ui->gridLayout->addWidget(bindValue(new QLabel("4"),"BW4"),4,4,1,1);
    this->ui->gridLayout->addWidget(bindValue(new QLabel("5"),"BW5"),4,5,1,1);
    this->ui->gridLayout->addWidget(bindValue(new QLabel("6"),"BW6"),4,6,1,1);



    this->ui->gridLayout_2->addWidget(new QLabel("gaindb"),0,0);
    this->ui->gridLayout_2->addWidget(new QLabel("slope"),1,0);
    this->ui->gridLayout_2->addWidget(new QLabel("slopedepthdb"),2,0);

    this->ui->gridLayout_2->addWidget(bindValue(new KawaiiLineEdit(),"gaindb"),0,1,1,1);
    this->ui->gridLayout_2->addWidget(bindValue(new KawaiiLineEdit(),"slope"),1,1,1,1);
    this->ui->gridLayout_2->addWidget(bindValue(new KawaiiLineEdit(),"slopedepthdb"),2,1,1,1);
}

QWidget* MaddeWindow::bindValue(QWidget *widget, QString keypath)
{
    ValueBinder* b =new ValueBinder(widget,keypath,this);
    valueMap[keypath] = b;
    connect(b,SIGNAL(valueChanged(QString,QVariant)),this,SLOT(input_valueChanged(QString,QVariant)));
    return widget;
}

void MaddeWindow::setValue(QString key,QVariant value)
{
    valueMap[key]->setValue(value);
    if((key.length()==2 && key[0]=='Q'))
    {
        QString key1 = key;
        key1.replace("Q","F");
        QString key2 = key;
        key2.replace("Q","BW");
        float n = valueMap[key1]->_value.toFloat();
        float d = value.toFloat();
        if(n>0 && d>0)
        valueMap[key2]->setValue(n/d);
        else
        valueMap[key2]->setValue(0);
    }
    if((key.length()==2 && key[0]=='F'))
    {
        QString key1 = key;
        key1.replace("F","Q");
        QString key2 = key;
        key2.replace("F","BW");
        float d = valueMap[key1]->_value.toFloat();
        float n = value.toFloat();
        if(n>0 && d>0)
        valueMap[key2]->setValue(n/d);
        else
        valueMap[key2]->setValue(0);
    }
    if((key.length()==3 && key[0]=='B' && key[1]=='W'))
    {
        QString key1 = key;
        key1.replace("BW","F");
        QString key2 = key;
        key2.replace("BW","Q");
        float d = valueMap[key1]->_value.toFloat();
        float n = value.toFloat();
        if(n>0 && d>0)
        valueMap[key2]->setValue(d/n);
        else
        valueMap[key2]->setValue(0);
    }

}

void MaddeWindow::input_valueChanged(QString key, QVariant value)
{
    this->setValue(key,value);
    emit valueChanged(key,value);
}

MaddeWindow::~MaddeWindow()
{
    delete ui;
}

void MaddeWindow::closeEvent(QCloseEvent *event) {
     emit closed();
     QMainWindow::closeEvent(event);
}

void MaddeWindow::updateRecentFileActions()
{
    QSettings settings;
    QStringList files = settings.value("recentMaddeFileList").toStringList();

    int numRecentFiles = qMin(files.size(), (int)MAXRECENTFILES);

    bool visible = false;

    for (int i = 0; i < numRecentFiles; ++i) {
        QString fileName = QFileInfo(files[i]).fileName();
        QString text = tr("&%1 %2").arg(i + 1).arg(fileName);
        _recentFileActs[i]->setText(text);
        _recentFileActs[i]->setData(files[i]);
        _recentFileActs[i]->setVisible(true);
        visible = true;
    }
    for (int j = numRecentFiles; j < MAXRECENTFILES; ++j)
        _recentFileActs[j]->setVisible(false);

    ui->menuRecent_files->setEnabled(visible);
}



ValueBinder::ValueBinder(QWidget* widget,QString name,MaddeWindow* parent) : QObject(parent), _widget(widget),_name(name)
{
    KawaiiLineEdit* lineEdit = qobject_cast<KawaiiLineEdit*>(widget);
    if(lineEdit)
    {
        connect(lineEdit,SIGNAL(editingFinished()),this,SLOT(lineEdit_editingFinished()));
        connect(lineEdit,SIGNAL(keyPressHooked(int)),this,SLOT(lineEdit_keyPressHooked(int)));
    }
    QCheckBox* checkBox= qobject_cast<QCheckBox*>(widget);
    if(checkBox)
    {
        connect(checkBox,SIGNAL(toggled(bool)),this,SLOT(checkBox_toggled(bool)));
    }
}

void ValueBinder::checkBox_toggled(bool value)
{
    emit valueChanged(_name,value);
}

void ValueBinder::lineEdit_keyPressHooked(int key)
{
    DEVLOG_DEBUG(_name);
    if(_name=="slope")
    {
        if(key==Qt::Key_Up)
        {
           emit valueChanged(_name,_value.toFloat() * 2);
        }
        else
        {
           emit valueChanged(_name,_value.toFloat() / 2);
        }
        return;
    }
    float increment = 10.0;
    if(_name.length()==2 && _name[0]=='A') increment = 1;
    if(_name.length()==2 && _name[0]=='Q') increment = 0.1;
    if(key==Qt::Key_Up)
    {
       emit valueChanged(_name,_value.toFloat() + increment);
    }
    else
    {
       emit valueChanged(_name,_value.toFloat() - increment);
    }

}

void ValueBinder::lineEdit_editingFinished()
{
    KawaiiLineEdit* lineEdit = qobject_cast<KawaiiLineEdit*>(_widget);
    if(lineEdit)
    {
        emit valueChanged(_name,QVariant(lineEdit->text()));
    }
}



void ValueBinder::setValue(QVariant value)
{
    _value = value;
    KawaiiLineEdit* lineEdit = qobject_cast<KawaiiLineEdit*>(_widget);
    if(lineEdit)
    {
#if 0
        if(_name=="slope") {
            float x = value.toFloat();
            QVariant value2 = ((int)(log(-x) * 100 + .5) / 100.0);
            lineEdit->setText(value2.toString());
        }
        else
#endif
        lineEdit->setText(value.toString());
    }
    QCheckBox* checkBox = qobject_cast<QCheckBox*>(_widget);
    if(checkBox)
    {
        checkBox->setChecked(value.toBool());
    }
    QLabel* label = qobject_cast<QLabel*>(_widget);
    if(label)
    {
        label->setText(value.toString()+"Hz");
    }
}

KawaiiLineEdit::KawaiiLineEdit() : QLineEdit()
{

}

void KawaiiLineEdit::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_Up || event->key() == Qt::Key_Down){
        emit keyPressHooked(event->key());
    }
    else{
        // default handler for event
        QLineEdit::keyPressEvent(event);
    }
}

void MaddeWindow::on_actionNew_triggered()
{
    _currentFileName = "";
    emit loadDefault();
    updateWindowTitle();
}

void MaddeWindow::addFileToRecentFiles(QString fileName)
{
    DEVLOG_DEBUG("addFileToRecentFiles: "+fileName);

    QSettings settings;
    QStringList files = settings.value("recentMaddeFileList").toStringList();
    files.removeAll(fileName);
    files.prepend(fileName);
    while (files.size() > MAXRECENTFILES)
       files.removeLast();

    foreach(QString file, files)
        DEVLOG_DEBUG("recent: "+file);

    settings.setValue("recentMaddeFileList", files);

    updateRecentFileActions();
}

void MaddeWindow::on_actionOpen_triggered()
{
    QString fileName = QFileDialog::getOpenFileName(this,
                                                    tr("Open Madde File"), "", tr("Madde Files (*.madde)"));

    if (!fileName.isEmpty())
    {
        addFileToRecentFiles(fileName);
        emit loadFile(fileName);
        _currentFileName = fileName;
        _lastMaddeDir = QFileInfo(fileName).absolutePath();
        updateWindowTitle();
    }
}

void MaddeWindow::openRecentFile()
{
    QAction *action = qobject_cast<QAction *>(sender());
    if (action)
    {
        QString fileName = action->data().toString();
        if(QFile(fileName).exists())
        {
            emit loadFile(fileName);
            _currentFileName = fileName;
            _lastMaddeDir = QFileInfo(fileName).absolutePath();
            updateWindowTitle();
        }
        else
        {
            QSettings settings;
            QStringList files = settings.value("recentMaddeFileList").toStringList();
            files.removeOne(fileName);
            settings.setValue("recentMaddeFileList", files);
            updateRecentFileActions();

            QMessageBox msgBox;
            msgBox.setText("The file \""+fileName+"\"does not exist.");
            msgBox.exec();
        }

    }
}

void MaddeWindow::on_actionSave_triggered()
{
    if (_currentFileName.isEmpty())
        on_actionSave_as_triggered();
    else
        emit saveToFile(_currentFileName);
}

void MaddeWindow::on_actionSave_as_triggered()
{
    QString fileName = QFileDialog::getSaveFileName(this,
                                                    tr("Save Madde File"), _lastMaddeDir, tr("Madde Files (*.madde)"));
    if (!fileName.isEmpty())
    {
        emit saveToFile(fileName);
        _currentFileName = fileName;
        _lastMaddeDir = QFileInfo(fileName).absolutePath();
        updateWindowTitle();
    }
}

void MaddeWindow::on_actionShow_F1_F2_map_triggered()
{
    if(_formantWindow) return;

    _formantWindow = new FormantMapWindow();
    _formantWindow->show();
    connect(_formantWindow,SIGNAL(mouseDown(float,float)),this,SLOT(formantWindow_mouseDown(float,float)));
    connect(_formantWindow,SIGNAL(mouseUp()),this,SLOT(formantWindow_mouseUp()));
    connect(_formantWindow,SIGNAL(closed()),this,SLOT(formantWindow_closed()));
}

void MaddeWindow::formantWindow_mouseDown(float f1, float f2)
{
    input_valueChanged("F1",f1);
    input_valueChanged("F2",f2);
    emit mouseEvent(1);
}

void MaddeWindow::formantWindow_mouseUp()
{
    emit mouseEvent(0);
}

void MaddeWindow::formantWindow_closed()
{
    delete _formantWindow;
    _formantWindow=NULL;
}

void MaddeWindow::updateWindowTitle()
{
    QString fileName = QFileInfo(_currentFileName).fileName();
    if(fileName.length()>0)
        setWindowTitle(fileName + " - MaddeLOID");
    else
        setWindowTitle("MaddeLOID");
}
